/**
 * @class   wosh::database::EncoderXML
 * @brief   
 *
 ****************************************************************************
 * @version $Id: EncoderXML.h 2067 2010-03-09 23:40:30Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_EncoderXML_H__
 #define __WOSH_EncoderXML_H__

 #include <woshDefs.h>
 #include <core/DataBase.h>
 #include <core/Variant.h>
 #include <core/Message.h>
 #include <core/Mutex.h>
 #include <core/Serialization.h>
 #include <core/LogContext.h>

 #include <framework/database/SerializableXML.h>
 #include <framework/database/EncoderXMLCommon.h>

 #include <map>

 #include <QtXml>
 #include <QByteArray>


namespace wosh {
 namespace database {

 #define _DataBaseXML_NAME					"EncoderXML"
 #define _DataBaseXML_TYPE					"wosh::database::EncoderXML"

 #define _DataBaseXML_PROTOCOL				"xml"
 #define _DataBaseXML_XmlRootNodeName		"WOSH"


class EncoderXML : public wosh::DataBase
 {
	WOSH_DATABASE(wosh::database::EncoderXML)

	public:

		EncoderXML();

		virtual ~EncoderXML();

	public:

		virtual std::string getProtocol() const			{ return _DataBaseXML_PROTOCOL; }

		virtual WRESULT loadObjects( std::vector<wosh::ISerializable*>& objects, const std::string& class_name, const std::string& archive_name );

		virtual WRESULT saveObjects( std::vector<wosh::ISerializable*>& objects, const std::string& archive_name );


	public:

		static WRESULT registerDataType( const std::string& class_name, wosh::database::EncoderXML_base* object );

		static wosh::database::EncoderXML_base* findEncoderFor( const std::string& tagname );


	public:

		template <class T>
		static long serializeTo( const T* object, char* output, long maxSize )
		 {
			QDomDocument doc("none");
			QDomElement rootNode = doc.createElement( object->getClassName() );
			doc.appendChild(rootNode);

			WRESULT ret = serializeTo( object, doc, rootNode, false );
			if ( WFAILED(ret) )
				return 0;

			QByteArray buffer = doc.toByteArray();
			if ( buffer.size() > maxSize ) {
				return -buffer.size();
			 }
#ifdef _MSC_VER
			strncpy_s(output, buffer.size(), buffer.data(), _TRUNCATE );
#else
			strncpy(output, buffer.data(), buffer.size() );
#endif
			return buffer.size();
		 }

		template <class T>
		static WRESULT deserializeFrom( T* object, const char* data, long maxSize )
		 {
			WRESULT ret = WRET_OK;
			QDomDocument doc("none");
			QByteArray xml_data(data, maxSize);
			bool validXml = doc.setContent(xml_data, false);
			if ( !validXml )
				ret = WRET_ERR_PARAM;

			std::string tagname = std::string( doc.documentElement().tagName().toLatin1().data() );
			if ( tagname == object->getClassName() ) {
				ret = deserializeFrom( object, doc.documentElement() );
			 }
			else {
				QDomNodeList nodesList = doc.documentElement().elementsByTagName( object->getClassName() );
				if ( nodesList.length() == 0 )				
					return WRET_ERR_INTERNAL;
				ret = deserializeFrom( object, nodesList.item(0).toElement() );
			 }
			return ret;
		 }


	public:

		template <class T>
		static WRESULT serializeTo( const T* object, QDomDocument& doc, QDomElement& contNode, bool compact )
		 {
			if ( EncoderXML::objectRegs.find( object->getClassName() ) == EncoderXML::objectRegs.end() ) {
				return WRET_ERR_PARAM;
			 }
			wosh::database::EncoderXML_base* encoder = EncoderXML::objectRegs[ std::string(object->getClassName()) ];

			return encoder->serializeTo( object, doc, contNode, compact );
		 }


		template <class T>
		static WRESULT deserializeFrom( T* object, const QDomElement& contNode )
		 {

			if ( EncoderXML::objectRegs.find( object->getClassName() ) == EncoderXML::objectRegs.end() ) {
				return WRET_ERR_PARAM;
			 }
			wosh::database::EncoderXML_base* encoder = EncoderXML::objectRegs[ std::string(object->getClassName()) ];

			return encoder->deserializeFrom( object, contNode );
		 }
	
		static wosh::database::EncoderXML_base* getCustomEncoder( std::string class_name )
		 {

			if ( EncoderXML::objectRegs.find( class_name ) == EncoderXML::objectRegs.end() ) {
				return NULL;
			 }
			return EncoderXML::objectRegs[ class_name ];
		 }


	public:

		WRESULT loadXmlDocument( QDomDocument& doc, const std::string& filename );

		WRESULT saveXmlDocument( QDomDocument& doc, const std::string& filename );


	protected:

		void freeObjecsRegs_();


	protected:

		wosh::LogContext Log;

		static std::map<std::string, wosh::database::EncoderXML_base*> objectRegs;
		static wosh::Mutex objRegsMux;


}; // class def

 }; // namespace database
}; // namespace wosh

#endif //__WOSH_EncoderXML_H__
